<template>
  <div class="container">
    <button @click="say()">{{ msg }}</button>
    <div>{{ name }}</div>
    <div>{{ obj }}</div>
    <div>{{ obj3 }}</div>
    <hr/>
    <div>{{ name1 }}</div>
    <div>{{ age }}</div>
    <div>{{ newAge }}</div>
    <button @click="updateName">修改数据</button>
    <hr/>
    <!-- 使用v-model绑定计算属性 -->
    <label>
      <input type="text" v-model="newAge1">
    </label>
    <hr/>
    <div>
      <p>count的值：{{ count }}</p>
      <button @click="add">改数据</button>
    </div>
    <div>
      <p>车主姓名---{{ obj4.name }}</p>
      <p>车主年龄---{{ obj4.age }}</p>
      <p>汽车品牌名称---{{ obj4.brand.name }}</p>
      <button @click="updateName4">改车主名字</button>
      <button @click="updateBrandName4">改汽车品牌名称</button>
    </div>
    <hr/>
    <div ref="dom">我是box</div>
    <ul>
      <li v-for="i in 4" :key="i" :ref="setDom">{{ i }}</li>
    </ul>
    <hr/>
  </div>

</template>

<script>
import {
  onBeforeMount,
  onMounted,
  reactive,
  ref,
  toRef,
  toRefs,
  computed,
  watch
} from 'vue'

export default {
  name: "Part1",
  // setup函数
  // setup 是一个新的组件选项，作为组件中使用组合API的起点。
  // 从组件生命周期来看，它的执行在组件实例创建之前vue2.x的beforeCreate执行。
  // 这就意味着在setup函数中 this 还不是组件实例，this 此时是 undefined
  // 在模版中需要使用的数据和函数，需要在 setup 返回。
  setup() {
    // api生命周期
    // setup 创建实例前
    // onBeforeMount 挂载DOM前
    // onMounted 挂载DOM后
    // onBeforeUpdate 更新组件前
    // onUpdated 更新组件后
    // onBeforeUnmount 卸载销毁前
    // onUnmounted 卸载销毁后
    onBeforeMount(() => {
      // console.log('DOM渲染前', document.querySelector('.container'))
    })
    onMounted(() => {
      // console.log('DOM渲染后1', document.querySelector('.container'))
    })
    onMounted(() => {
      // console.log('DOM渲染后2', document.querySelector('.container'))
    })
    // console.log('setup执行了')
    // console.log(this)
    // 定义数据和函数
    const msg = 'Hello World'
    const say = () => {
      console.log(msg)
    }
    // reactive函数，它可以定义一个复杂数据类型，成为响应式数据
    const obj = reactive({
      name: 'Jackson',
      age: 18
    })
    // console.log(obj)
    // toRef是函数，转换响应式对象中某个属性为单独响应式数据，并且值是关联的
    const name = toRef(obj, 'name')
    // toRefs是函数，转换响应式对象中所有属性为单独响应式数据，对象成为普通对象，并且值是关联的
    const obj3 = toRefs(obj)
    // ref函数，常用于简单数据类型定义为响应式数据
    // 再修改值，获取值的时候，需要.value
    // 在模板中使用ref申明的响应式数据，可以省略.value
    const name1 = ref('Harden')
    // console.log(name1);
    // console.log(obj3)
    const updateName = () => {
      console.log('updateName')
      name1.value = 'Paul'
      obj.name = 'Mike'
    }
    const age = ref(10)
    const age1 = ref(8)
    // computed函数，是用来定义计算属性的，计算属性不能修改
    // 总结：计算属性两种用法
    // 给computed传入函数，返回值就是计算属性的值
    // 给computed传入对象，get获取计算属性的值，set监听计算属性改变。
    const newAge = computed(() => {
      return age.value * age.value
    })
    const newAge1 = computed({
      get() {
        return age1.value + 2
      },
      set(value) {
        age1.value = value - 2
      }
    })
    // console.log(newAge1);
    const count = ref(0)
    const add = () => {
      count.value++
    }
    const obj4 = reactive({
      name: 'Cook',
      age: 10,
      brand: {
        id: 1,
        name: '奔驰'
      }
    })
    const updateName4 = () => {
      obj4.name = 'Bob'
    }
    const updateBrandName4 = () => {
      obj4.brand.name = '奥迪'
    }
    // 当你需要监听数据的变化就可以使用watch
    // 1. 监听一个ref数据
    // 1.1 第一个参数  需要监听的目标
    // 1.2 第二个参数  改变后触发的函数
    // watch(count, (newVal,oldVal)=>{
    //   console.log(newVal,oldVal)
    // })
    // 3. 监听多个数据的变化
    // watch([count, obj], ()=>{
    //   console.log('监听多个数据改变了')
    // })
    // 4. 此时监听对象中某一个属性的变化 例如：obj.name
    // 需要写成函数返回该属性的方式才能监听到
    // watch(()=>obj.name,()=>{
    //   console.log('监听obj.name改变了')
    // })
    watch(obj4, () => {
      console.log('obj4数据改变了')
    })
    watch(() => obj4.brand, () => {
      console.log('obj4.brand4数据改变了')
    }, {
      // 深度监听
      deep: true,
      // 默认触发
      immediate: true
    })
    watch(() => obj4.name, () => {
      console.log('obj4.车主姓名数据改变了')
    })
    // 1. 获取单个元素
    // 1.1 先定义一个空的响应式数据ref定义的
    // 1.2 setup中返回该数据，你想获取那个dom元素，在该元素上使用ref属性绑定该数据即可
    // 单个元素：先申明ref响应式数据，返回给模版使用，通过ref绑定数据
    // 遍历的元素：先定义一个空数组，定一个函数获取元素，返回给模版使用，通过ref绑定这个函数
    // 有一个边界问题：组件更新的时候会重复的设置dom元素给数组
    const dom = ref(null)
    const domList = []
    const setDom = (el) => {
      domList.push(el)
    }
    onMounted(() => {
      console.log(dom.value)
      console.log(domList)
    })
    return {
      msg,
      say,
      obj,
      updateName,
      name,
      obj3,
      name1,
      age,
      newAge,
      age1,
      newAge1,
      obj4,
      add,
      updateName4,
      updateBrandName4,
      count,
      dom,
      setDom
    }
  },
  beforeCreate() {
    // console.log('beforeCreate执行了')
    // console.log(this)
  }
}
</script>

<style scoped>
</style>
